﻿using System.Web;

namespace BigfootMVC.Helpers
{
    public class ViewHelper
    {

        private HttpServerUtility server;
        private HttpRequest request;
        private HttpResponse response;

        /// <summary>
        /// This constructor creates a new view helper class using the current HttpContext
        /// </summary>
        public ViewHelper()
        {
            server = HttpContext.Current.Server;
            request = HttpContext.Current.Request;
            response = HttpContext.Current.Response;
        }

        /// <summary>
        /// This constructor creates a new view helper class using the request response and sever objects
        /// passed into it. This is useful when abstracting or moqing these objects
        /// </summary>
        public ViewHelper(HttpRequest request, HttpResponse response, HttpServerUtility server)
        {
            this.server = server;
            this.request = request;
            this.response = response;
        }

        /// <summary>
        /// Contains the HTML helpers you can use in the views. It is an alias class that provides easy access to the HTMLHelper class.
        /// </summary>
        public HtmlHelper Html { get { return _html ?? (_html = new HtmlHelper()); } }
        private HtmlHelper _html;

        /// <summary>
        /// Contains the Javascript helpers you can use in the views. It is an alias class that provides easy access to the JSHelper class.
        /// </summary>
        public JSHelper JS { get { return _js ?? (_js = new JSHelper()); } }
        private JSHelper _js;

        /// <summary>
        /// This is a general purpose html tag builder class. It is an alias class that provides easy access to the TagBuilder class.
        /// </summary>
        public TagBuilder TB (string tagName) { return new TagBuilder(tagName); }
        
        /// <summary>
        /// Creates a new AJAX request object you can build on in order to make ajax call to the server
        /// </summary>
        /// <param name="url">The url agains which you are executing the ajax request</param>
        public AjaxRequest Ajax(string url) { return AjaxRequest.Create(url); }

        /// <summary>
        /// Creates a partial from. Partial forms are a way to make field groups within a form behave like a form
        /// for the purposes of validation, and POST.
        /// </summary>
        /// <param name="formId">The element id that wraps the field group (i.e. div etc)</param>
        /// <returns>A script to ouputed on the page</returns>
        public string CreatePartialForm(string formId) { return JS.CreatePartialForm(formId); }

        /// <summary>
        /// Creates a partial from. Partial forms are a way to make field groups within a form behave like a form
        /// for the purposes of validation, and POST.
        /// </summary>
        /// <param name="formId">The element id that wraps the field group (i.e. div etc)</param>
        /// <param name="addScriptTag">Determines whether to add the script tag</param>
        /// <returns>A script to ouputed on the page</returns>
        public string CreatePartialForm(string formId, bool addScriptTag) { return JS.CreatePartialForm(formId, addScriptTag); }

        /// <summary>
        /// Converts a form into an ajax form
        /// </summary>
        /// <param name="formName">The name of the form</param>
        /// <param name="postUrl">The url where the form will be posted</param>
        public AjaxForm CreateAjaxForm(string formName, string postUrl)
        {
            return AjaxForm.Create(formName, postUrl);
        }

        /// <summary>
        /// Submits a partial from. Partial forms are a way to make field groups "Partial Form" within a form behave like a form
        /// for the purposes of validation, and POST.
        /// </summary>
        /// <param name="formId">The element id that wraps the field group "Partial Form" (i.e. div etc)</param>
        /// <param name="url">The url you would like to submit the form to</param>
        /// <returns>AJAX Request object upon which you can build other actions, like clearing the contents of a field upon callback etc.</returns>
        public AjaxRequest SubmitPartialForm(string formId, string url) { return JS.SubmitPartialForm(formId, url); }

        /// <summary>
        /// Submits a partial from. Partial forms are a way to make field groups "Partial Form" within a form behave like a form
        /// for the purposes of validation, and POST.
        /// </summary>
        /// <param name="formId">The element id that wraps the field group "Partial Form" (i.e. div etc)</param>
        /// <param name="url">The url you would like to submit the form to</param>
        /// <param name="validate">Determines weather to validate the form before submission or not</param>
        /// <returns>AJAX Request object upon which you can build other actions, like clearing the contents of a field upon callback etc.</returns>
        public AjaxRequest SubmitPartialForm(string formId, string url, bool validate) { return JS.SubmitPartialForm(formId, url, validate); }

        /// <summary>
        /// A helper builder function that outputs the text only if the specified condition is true
        /// (i.e. <%=RenderIf(user.HasGrups, user.GroupString)%>
        /// </summary>
        /// <param name="condition">The condition that determines weather the text is rendered or not</param>
        /// <param name="text">The text / html to render if the condition is true </param>
        /// <returns>Returns the RenderIfBuilder upon which you can further build with an .else statement other if conditions etc.</returns>
        public RenderIfBuilder RenderIf(bool condition, string text) { return Html.RenderIf(condition, text); }

        /// <summary>
        /// HtmlEncode the string for output
        /// </summary>
        /// <param name="data">The string to be encoded</param>
        /// <returns>HtmlEncoded string</returns>
        public string E(string data)
        {
            return HttpUtility.HtmlEncode(data);
        }

        /// <summary>
        /// Quick access to the String.Format function
        /// </summary>
        /// <param name="value">The string where the values will be inserted i.e. The bird flew {0} miles</param>
        /// <param name="values">The values to merge with the format string</param>
        /// <returns>The formated string</returns>
        public string F(string value, params string[] values)
        {
            return string.Format(value, values);
        }

        /// <summary>
        /// Helps in the creation of a unique id to later be used in collection binding
        /// </summary>
        /// <param name="prefix">The prefix that ties the colleciton together</param>
        /// <param name="id">The unique id of the collection item</param>
        /// <param name="fieldName">The name of the field to bind to for a certain item</param>
        public string ColId(string prefix, string id, string fieldName)
        {
            return prefix + "_" + id + "_" + fieldName;
        }

        /// <summary>
        /// Helps in the creation of a unique id to later be used in collection binding
        /// </summary>
        /// <param name="prefix">The prefix that ties the colleciton together</param>
        /// <param name="id">The unique id of the collection item</param>
        /// <param name="fieldName">The name of the field to bind to for a certain item</param>
        public string ColId(string prefix, int id, string fieldName)
        {
            return prefix + "_" + id + "_" + fieldName;
        }

        /// <summary>
        /// Creates a properly formated url parameter. 
        /// </summary>
        /// <param name="paramName">The name of the url parameter</param>
        /// <param name="value">The value of the url parameter</param>
        /// <returns>The properly formatted parameter i.e. parameter=value</returns>
        public string UrlP(string paramName, string value)
        {
            return paramName + "=" + value;
        }

        /// <summary>
        /// Creates a properly formated url parameter. 
        /// </summary>
        /// <param name="paramName">The name of the url parameter</param>
        /// <param name="value">The integer value of the url parameter</param>
        /// <returns>The properly formatted parameter i.e. parameter=value</returns>
        public string UrlP(string paramName, int value)
        {
            return paramName + "=" + value;
        }

        /// <summary>
        /// Easy access to the UrlBuilder class. Aids in the fluid creation of urls and url parameters
        /// </summary>
        public UrlBuilder QS { get { return new UrlBuilder(); } }
        
        /// <summary>
        /// Class used to aid in the collection of posted values from the request. First it tries the QueryString and second it tries the form collection
        /// </summary>
        public PostHelper Post
        {
            get
            {
                return _values ?? (_values = new PostHelper(request));
            }
        }
        private PostHelper _values;

        /// <summary>
        /// Render a UserControl onto a temporary page, execute it and return the resulting markup string.
        /// </summary>
        /// <param name="viewRelativePath">The relative path of the user control to render. i.e. ~/views/test.ascx</param>
        /// <returns>The rendered string ouput</returns>
        public string RenderUserControl(string viewRelativePath)
        {
            return WebApp.RenderViewToString(server, viewRelativePath, null, null, null);
        }

        /// <summary>
        /// Render a UserControl onto a temporary page, execute it and return the resulting markup string.
        /// </summary>
        /// <param name="viewRelativePath">The relative path of the user control to render. i.e. ~/views/test.ascx</param>
        /// <param name="data">Assigns this object to the ModelData property (if it exists) of the view being rendered</param>
        /// <returns>The rendered string ouput</returns>
        public string RenderUserControl(string viewRelativePath, object data)
        {
            return WebApp.RenderViewToString(server, viewRelativePath, data, null, null);
        }

        /// <summary>
        /// Render a UserControl onto a temporary page, execute it and return the resulting markup string.
        /// </summary>
        /// <param name="viewRelativePath">The relative path of the user control to render. i.e. ~/views/test.ascx</param>
        /// <param name="data">Assigns this object to the ModelData property (if it exists) of the view being rendered</param>
        /// <param name="loadField1Name">Assigns the loadField1Data value to a property or field with this name on the rendered view</param>
        /// <param name="loadField1Data">Value to assign the loadField1Name property or field</param>
        /// <returns>The rendered string ouput</returns>
        public string RenderUserControl(string viewRelativePath, object data, string loadField1Name, object loadField1Data)
        {
            return WebApp.RenderViewToString(server, viewRelativePath, data, loadField1Name, loadField1Data);
        }

        /// <summary>
        /// Render a UserControl onto the page only if the specified condition is met
        /// </summary>
        /// <param name="condition">The condition that must be met in order for the view to be rendered</param>
        /// <param name="viewRelativePath">The name of the view within the current controller to render</param>
        /// <param name="data">The data to be used as the view's model</param>
        /// <returns>The rendered html output of the view</returns>
        public string RenderUserControlIf(bool condition, string viewRelativePath, object data)
        {
            return condition ? WebApp.RenderViewToString(server, viewRelativePath, data, null, null) : "";
        }

        /// <summary>
        /// Render a UserControl onto the page only if the specified condition is met
        /// </summary>
        /// <param name="condition">The condition that must be met in order for the view to be rendered</param>
        /// <param name="viewRelativePath">The name of the view within the current controller to render</param>
        /// <param name="data">The data to be used as the view's model</param>
        /// <param name="loadField1Name">Assigns the loadField1Data value to a property or field with this name on the rendered view</param>
        /// <param name="loadField1Data">Value to assign the loadField1Name property or field</param>
        /// <returns>The rendered html output of the view</returns>
        public string RenderUserControlIf(bool condition, string viewRelativePath, object data, string loadField1Name, object loadField1Data)
        {
            return condition ? WebApp.RenderViewToString(server, viewRelativePath, data, null, null) : "";
        }

        /// <summary>
        /// Creates a DIV element with the provided content and assigns the provided css classes
        /// </summary>
        /// <param name="content">The content for the DIV</param>
        /// <param name="classes">CSS Classes to add</param>
        /// <returns>A TagBuilder</returns>
        public TagBuilder DIV(string content, string classes)
        {
            return Html.DIV(content, classes);
        }

        /// <summary>
        /// Creates a DIV element y calling string.format on the content and assigns the provided css classes
        /// </summary>
        /// <param name="content">The content for the DIV</param>
        /// <param name="classes">CSS Classes to add</param>
        /// <param name="formatValues">The values to merge with the content</param>
        /// <returns>A TagBuilder</returns>
        public TagBuilder DIV(string content, string classes, params string[] formatValues)
        {
            return Html.DIV(string.Format(content, formatValues), classes);
        }

        /// <summary>
        /// Creates a SPAN element with the provided content and assigns the provided css classes
        /// </summary>
        /// <param name="content">The content for the SPAN</param>
        /// <param name="classes">CSS Classes to add</param>
        /// <returns>A TagBuilder</returns>
        public TagBuilder SPAN(string content, string classes)
        {
            return Html.SPAN(content, classes);
        }

        /// <summary>
        /// Creates a SPAN element with the provided by calling string.format on the content and assigns the provided css classes
        /// </summary>
        /// <param name="content">The content for the SPAN</param>
        /// <param name="classes">CSS Classes to add</param>
        /// <param name="formatValues">The values to merge with the content</param>
        /// <returns>A TagBuilder</returns>
        public TagBuilder SPAN(string content, string classes, params string[] formatValues)
        {
            return Html.SPAN(string.Format(content, formatValues), classes);
        }


        /// <summary>
        /// Convert an object into a JSON string
        /// </summary>
        public string ToJson(object data)
        {
            return Serializer.ToJson(data);
        }

        /// <summary>
        /// Converts a JSON string into an object
        /// </summary>
        /// <typeparam name="T">The type to desirialize the string into</typeparam>
        /// <param name="jsonString">The JSON string to deserialize</param>
        public T FromJson<T>(string jsonString)
        {
            return Serializer.FromJson<T>(jsonString);
        }

        /// <summary>
        /// Creates a javascript reference
        /// </summary>
        public string JSReference(string url)
        {
            return Html.JSReference(url);
        }

        /// <summary>
        /// Creates a CSS reference
        /// </summary>
        public string CSSReference(string url)
        {
            return Html.CSSReference(url);
        }
    }
}
